home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fsutil / fsutilRecovery.c < prev    next >
C/C++ Source or Header  |  1991-03-30  |  33KB  |  1,172 lines

  1. /* 
  2.  * fsRecovery.c
  3.  *
  4.  *    Routines for filesytem recovery.  A file server keeps state about
  5.  *    client use, and this needs to be recovered after the server reboots.
  6.  *    The first routine, Fsutil_Reopen, goes through a sequence of steps that
  7.  *    a client makes in order to help the server in this way.  Other
  8.  *    routines are used by other parts of the filesystem to wait for
  9.  *    recovery to happen, and are typically invoked after a remote
  10.  *    operation fails due to a communication failure.  These are
  11.  *    Fsutil_WantRecovery, and Fsutil_WaitForRecovery.  The routine Fsutil_WaitForHost
  12.  *    is combines these two calls and is used by routines outside
  13.  *    the filesystem, i.e. when vm waits on swap files.
  14.  *
  15.  * Copyright 1987 Regents of the University of California.
  16.  * All rights reserved.
  17.  * Permission to use, copy, modify, and distribute this
  18.  * software and its documentation for any purpose and without
  19.  * fee is hereby granted, provided that the above copyright
  20.  * notice appear in all copies.  The University of California
  21.  * makes no representations about the suitability of this
  22.  * software for any purpose.  It is provided "as is" without
  23.  * express or implied warranty.
  24.  */
  25.  
  26. #ifndef lint
  27. static char rcsid[] = "$Header: /sprite/src/kernel/fsutil/RCS/fsutilRecovery.c,v 9.16 91/03/30 17:17:05 mgbaker Exp $ SPRITE (Berkeley)";
  28. #endif not lint
  29.  
  30. #include <sprite.h>
  31. #include <fs.h>
  32. #include <fsutil.h>
  33. #include <fsprefix.h>
  34. #include <fsio.h>
  35. #include <fsrmt.h>
  36. #include <fsNameOps.h>
  37. #include <fsStat.h>
  38. #include <recov.h>
  39. #include <hash.h>
  40. #include <rpc.h>
  41. #include <vm.h>
  42.  
  43. #include <string.h>
  44. #include <stdio.h>
  45.  
  46.  
  47. static void ReopenHandles _ARGS_((int serverID));
  48. static void RecoveryComplete _ARGS_((Fsutil_RecoveryInfo *recovPtr, 
  49.             ReturnStatus status));
  50. static void RecoveryNotify _ARGS_((Fsutil_RecoveryInfo *recovPtr));
  51. static Boolean RecoveryFailed _ARGS_((Fsutil_RecoveryInfo *recovPtr));
  52. static Boolean OkToScavenge _ARGS_((register Fsutil_RecoveryInfo *recovPtr));
  53. static void RecoveryDone _ARGS_((int serverID));
  54. extern Boolean RemoteHandle _ARGS_((Fs_HandleHeader *hdrPtr));
  55. extern ReturnStatus RecoveryWait _ARGS_((Fsutil_RecoveryInfo *recovPtr));
  56.  
  57. /*
  58.  * The recovery state for each file is monitored.
  59.  */
  60. #define LOCKPTR (&recovPtr->lock)
  61.  
  62. /*
  63.  * Flags for the recovery state.
  64.  *    RECOVERY_NEEDED        The handle needs to be re-opened at the server.
  65.  *    RECOVERY_COMPLETE    The recovery actions have been completed.
  66.  *    RECOVERY_FAILED        The last re-open attempt failed.
  67.  */
  68. #define RECOVERY_NEEDED        0x1
  69. #define RECOVERY_COMPLETE    0x2
  70. #define RECOVERY_FAILED        0x4
  71.  
  72. /*
  73.  * A global counter of the clients active in recovery is kept.
  74.  * This is used to control print statements so we aren't noisey
  75.  * in the middle of recovery, but only at the beginning and end.
  76.  */
  77. int fsutil_NumRecovering = 0;
  78.  
  79.  
  80. /*
  81.  *----------------------------------------------------------------------
  82.  *
  83.  * Fsutil_Reopen --
  84.  *
  85.  *    Re-establish state with a file server.  First the prefixes for
  86.  *     the server are re-opened, then the handle table is scanned and
  87.  *    all handles from that server are re-opened.  We are called via
  88.  *    the recovery callbacks.  As a special favor to the VM module
  89.  *    we tell it after we have recovered state so that it can
  90.  *    recover after the swap server.
  91.  *
  92.  * Results:
  93.  *    None.
  94.  *
  95.  * Side effects:
  96.  *    None by this routine itself, but when this returns the routines
  97.  *    it has called will have reestablished state with the server.
  98.  *
  99.  *----------------------------------------------------------------------
  100.  */
  101. /*ARGSUSED*/
  102. void
  103. Fsutil_Reopen(serverID, clientData)
  104.     int serverID;        /* Server we are recovering with */
  105.     ClientData clientData;    /* IGNORED */
  106. {
  107.     /*
  108.      * Ensure only one instance of Fsutil_Reopen by doing a set-and-test.
  109.      */
  110.     if (Recov_SetClientState(serverID, SRV_RECOV_IN_PROGRESS)
  111.         & SRV_RECOV_IN_PROGRESS) {
  112.     return;
  113.     }
  114.     /*
  115.      * Recover the prefix table.
  116.      */
  117.     Fsprefix_Reopen(serverID);
  118.     /*
  119.      * Wait for opens in progress, then block opens.
  120.      */
  121.     Fsprefix_RecoveryCheck(serverID);
  122.     /*
  123.      * Recover file handles
  124.      */
  125.     ReopenHandles(serverID);
  126.     /*
  127.      * Tell the server we're done.
  128.      */
  129.     RecoveryDone(serverID);
  130.     /*
  131.      * Allow regular opens.
  132.      */
  133.     Fsprefix_AllowOpens(serverID);
  134.     /*
  135.      * Clear the recovery bit before kicking processes.  Some processes
  136.      * may be locked down doing pseudo-device request/response, and the
  137.      * proc wakeup call will block on them.  To prevent deadlock we
  138.      * have to mark recovery as complete first.
  139.      */
  140.     Recov_ClearClientState(serverID, SRV_RECOV_IN_PROGRESS);
  141.     /*
  142.      * Kick all processes in case any are blocking on I/O
  143.      */
  144.     Proc_WakeupAllProcesses();
  145.     /*
  146.      * Tell VM that we have recovered in case this was the swap server.
  147.      */
  148.     Vm_Recovery();
  149. }
  150.  
  151. /*
  152.  *----------------------------------------------------------------------------
  153.  *
  154.  * ReopenHandles --
  155.  *
  156.  *    Called after the prefix table handles for the given server
  157.  *    have been recovered.  This scans the handle table twice
  158.  *    to recover I/O handles and streams.  The first pass re-opens
  159.  *    the I/O handles, and then streams are done.  A file-type specific
  160.  *    routine is called to do the reopen.  If the recovery fails this
  161.  *    logs a warning message and marks the handle as invalid.  A final
  162.  *    third pass over the handles is done to wakeup processes that are
  163.  *    waiting on recovery.
  164.  *
  165.  * Results:
  166.  *    None.
  167.  *
  168.  * Side effects:
  169.  *    This will invalidate handles for which recovery fails.  Invalid
  170.  *    I/O handles are removed from the handle table, while invalid
  171.  *    streams are left around because they get removed at close-time.
  172.  *
  173.  *----------------------------------------------------------------------------
  174.  */
  175.  
  176. static void
  177. ReopenHandles(serverID)
  178.     int        serverID;    /* The to re-establish contact with. */
  179. {
  180.     Hash_Search            hashSearch;
  181.     register    Fs_HandleHeader    *hdrPtr;
  182.     register    Fs_Stream    *streamPtr;
  183.     register    Fsrmt_IOHandle *rmtHandlePtr;
  184.     ReturnStatus        status = SUCCESS;
  185.     Boolean            printed = FALSE;
  186.     int                succeeded = fs_Stats.recovery.succeeded;
  187.     int                failed = fs_Stats.recovery.failed;
  188.  
  189.     Hash_StartSearch(&hashSearch);
  190.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  191.      hdrPtr != (Fs_HandleHeader *) NIL;
  192.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  193.      if ((hdrPtr->fileID.type != FSIO_STREAM) &&
  194.          (hdrPtr->fileID.serverID == serverID)) {
  195.         if (!RemoteHandle(hdrPtr)) {
  196.         panic("ReopenHandles, local I/O handle at remote server?\n");
  197.         }
  198.         if (!printed) {
  199.         Net_HostPrint(serverID, "- recovering handles\n");
  200.         printed = TRUE;
  201.         }
  202. #ifdef NOTDEF
  203.  
  204. /*
  205.  * For debugging it would be nice to be able to check for this, but
  206.  * FS_HANDLE_INVALID isn't defined here.
  207.  */
  208.         if (hdrPtr->flags & FS_HANDLE_INVALID) {
  209.         printf("Attempting to reopen invalid handle!!!\n");
  210.         }
  211. #endif NOTDEF
  212.         status = (*fsio_StreamOpTable[hdrPtr->fileID.type].reopen)(hdrPtr,
  213.         rpc_SpriteID, (ClientData)NIL, (int *)NIL, (ClientData *)NIL);
  214.         RecoveryComplete(&(((Fsrmt_IOHandle *)hdrPtr)->recovery),
  215.                 status);
  216.         /*
  217.          * If we removed the handle because it was no longer needed,
  218.          * we can't try unlocking it.
  219.          */
  220.         if (status != FS_NO_HANDLE) {
  221.         Fsutil_HandleUnlock(hdrPtr);
  222.         }
  223.         switch (status) {
  224.         case SUCCESS:
  225.             break;
  226.         case FS_NO_HANDLE:
  227.             /* We didn't need to recover this. */
  228.             break;
  229.         case RPC_SERVICE_DISABLED:
  230.         case RPC_TIMEOUT:
  231.             goto reopenReturn;
  232.         case FS_FILE_REMOVED:
  233.             /*
  234.              * No noisy message, this is a common case.
  235.              */
  236.             break;
  237.         default:
  238.             Fsutil_FileError(hdrPtr, "Reopen failed ", status);
  239.             break;
  240.         }
  241.     } else {
  242.         Fsutil_HandleUnlock(hdrPtr);
  243.     }
  244.     }
  245.     /*
  246.      * Now go through and recover streams, once we've gotten the regular
  247.      * I/O handles re-opened.  This ensures that the I/O handle will be
  248.      * around on the server when it re-creates our streams.  If recovery
  249.      * fails on a stream we invalidate its handle, but don't remove it
  250.      * because that happens in the top-level close routine.
  251.      */
  252.     Hash_StartSearch(&hashSearch);
  253.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  254.      hdrPtr != (Fs_HandleHeader *) NIL;
  255.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  256.     if ((hdrPtr->fileID.type == FSIO_STREAM) &&
  257.          (hdrPtr->fileID.serverID == serverID)) {
  258.         streamPtr = (Fs_Stream *)hdrPtr;
  259.         rmtHandlePtr = (Fsrmt_IOHandle *)streamPtr->ioHandlePtr;
  260.  
  261.         if (rmtHandlePtr == (Fsrmt_IOHandle *)NIL) {
  262.         Fsutil_FileError((Fs_HandleHeader *)streamPtr,
  263.             "ReopenHandles: NIL I/O handle", 0);
  264.         } else if (!RemoteHandle((Fs_HandleHeader *)rmtHandlePtr)) {
  265.         panic( "ReopenHandles: local I/O handle for remote stream?\n");
  266.         } else if (RecoveryFailed(&rmtHandlePtr->recovery)) {
  267.         Fsutil_HandleInvalidate((Fs_HandleHeader *)streamPtr);
  268.         } else {
  269.         status = Fsio_StreamReopen((Fs_HandleHeader *)streamPtr,
  270.                 rpc_SpriteID, (ClientData)NIL, (int *)NIL,
  271.                 (ClientData *)NIL);
  272.         if (status != SUCCESS) {
  273.             Fsutil_FileError((Fs_HandleHeader *)streamPtr,
  274.             "Reopen failed", status);
  275.             Fsutil_FileError(streamPtr->ioHandlePtr,"I/O handle",
  276.                 SUCCESS);
  277.             if ((status == RPC_TIMEOUT) ||
  278.             (status == RPC_SERVICE_DISABLED)) {
  279.             Fsutil_HandleUnlock(streamPtr);
  280.             goto reopenReturn;
  281.             }
  282.             Fsutil_HandleInvalidate((Fs_HandleHeader *)streamPtr);
  283.         }
  284.         }
  285.     }
  286.     Fsutil_HandleUnlock(hdrPtr);
  287.     }
  288.     /*
  289.      * Now we notify processes waiting on I/O handles, and invalidate
  290.      * those I/O handles which failed recovery.
  291.      */
  292.     Hash_StartSearch(&hashSearch);
  293.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  294.      hdrPtr != (Fs_HandleHeader *) NIL;
  295.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  296.      if (!RemoteHandle(hdrPtr)) {
  297.          Fsutil_HandleUnlock(hdrPtr);
  298.      } else {
  299.          RecoveryNotify(&((Fsrmt_IOHandle *)hdrPtr)->recovery);
  300.          if (RecoveryFailed(&((Fsrmt_IOHandle *)hdrPtr)->recovery)) {
  301.          Fsutil_HandleInvalidate(hdrPtr);
  302.          }
  303.          Fsutil_HandleUnlock(hdrPtr);
  304.      }
  305.     }
  306. reopenReturn:
  307.     if (status != SUCCESS) {
  308.     Net_HostPrint(serverID, "Recovery failed: ");
  309.     Fsutil_PrintStatus(status);
  310.     printf("\n");
  311.     } else if (printed) {
  312.     Net_HostPrint(serverID, "Recovery complete");
  313.     printf(" %d handles reopened", fs_Stats.recovery.succeeded - succeeded);
  314.     if (fs_Stats.recovery.failed - failed > 0) {
  315.         printf(" %d failed reopens", fs_Stats.recovery.failed - failed);
  316.     }
  317.     printf("\n");
  318.     }
  319. }
  320.  
  321. /*
  322.  *----------------------------------------------------------------------
  323.  *
  324.  * Fsutil_RecoveryInit --
  325.  *
  326.  *    This routine is called to reset the recovery state for
  327.  *    a handle when it is first set up.
  328.  *
  329.  * Results:
  330.  *    None.
  331.  *
  332.  * Side effects:
  333.  *    Zero's out the struct.
  334.  *
  335.  *----------------------------------------------------------------------
  336.  */
  337. void
  338. Fsutil_RecoveryInit(recovPtr)
  339.     register Fsutil_RecoveryInfo    *recovPtr;    /* Recovery state */
  340. {
  341.     bzero((Address) recovPtr, sizeof(Fsutil_RecoveryInfo));
  342.     Sync_LockInitDynamic(&recovPtr->lock, "fs:recoveryLock");
  343. }
  344.  
  345. /*
  346.  *----------------------------------------------------------------------
  347.  *
  348.  * Fsutil_RecoverySyncLockCleanup --
  349.  *
  350.  *    This routine is called when removing a handle to .
  351.  *
  352.  * Results:
  353.  *    None.
  354.  *
  355.  * Side effects:
  356.  *    Zero's out the struct.
  357.  *
  358.  *----------------------------------------------------------------------
  359.  */
  360. /*ARGSUSED*/
  361. void
  362. Fsutil_RecoverySyncLockCleanup(recovPtr)
  363.     Fsutil_RecoveryInfo    *recovPtr;    /* Recovery state */
  364. {
  365.     Sync_LockClear(&recovPtr->lock);
  366. }
  367.  
  368. /*
  369.  *----------------------------------------------------------------------
  370.  *
  371.  * RemoteHandle --
  372.  *
  373.  *    This checks the type of a handle to see if it is remote and thus
  374.  *    has a Fsrmt_IOHandle structure embedded into it.  Only these
  375.  *    kinds of handles are manipulated by the recovery routines.
  376.  *
  377.  * Results:
  378.  *    TRUE if the handle has a remote server.
  379.  *
  380.  * Side effects:
  381.  *    None.
  382.  *
  383.  *----------------------------------------------------------------------
  384.  */
  385. Boolean
  386. RemoteHandle(hdrPtr)
  387.     Fs_HandleHeader *hdrPtr;
  388. {
  389.     switch(hdrPtr->fileID.type) {
  390.     case FSIO_RMT_FILE_STREAM:
  391.     case FSIO_RMT_DEVICE_STREAM:
  392.     case FSIO_RMT_PIPE_STREAM:
  393.     case FSIO_RMT_PSEUDO_STREAM:
  394.     case FSIO_PFS_NAMING_STREAM:
  395.     case FSIO_RMT_PFS_STREAM:
  396.     case FSIO_CONTROL_STREAM:
  397.     case FSIO_PFS_CONTROL_STREAM:
  398.         return(TRUE);
  399.     default:
  400.         return(FALSE);
  401.     }
  402. }
  403.  
  404. /*
  405.  *----------------------------------------------------------------------
  406.  *
  407.  * Fsutil_WaitForHost --
  408.  *
  409.  *    Wait until recovery actions have completed for the stream.
  410.  *    This will return failure codes if the recovery aborts.
  411.  *    If the non-blocking flag is passed in this just marks the
  412.  *    handle as needing recovery and returns SUCCESS.
  413.  *
  414.  * Results:
  415.  *    SUCCESS unless there was a recovery error.
  416.  *
  417.  * Side effects:
  418.  *    Block the process.
  419.  *
  420.  *----------------------------------------------------------------------
  421.  */
  422. ReturnStatus
  423. Fsutil_WaitForHost(streamPtr, flags, rpcStatus)
  424.     Fs_Stream    *streamPtr;
  425.     int        flags;        /* 0 or FS_NON_BLOCKING */
  426.     ReturnStatus rpcStatus;    /* Status that caused us to need recovery. */
  427. {
  428.     register Fs_HandleHeader *hdrPtr = streamPtr->ioHandlePtr;
  429.     register ReturnStatus status;
  430.  
  431.     Fsutil_WantRecovery(hdrPtr);
  432.     if (flags & FS_NON_BLOCKING) {
  433.     status = SUCCESS;
  434.     } else {
  435.     status = Fsutil_WaitForRecovery(hdrPtr, rpcStatus);
  436.     }
  437.     return(status);
  438. }
  439.  
  440. /*
  441.  *----------------------------------------------------------------------
  442.  *
  443.  * Fsutil_WantRecovery --
  444.  *
  445.  *    This routine is called when an error has occurred trying to
  446.  *    contact the file's IO server indicating that recovery actions
  447.  *    should take place when the server comes back.  We depend on
  448.  *    recovery call-backs already being installed as we don't even
  449.  *    mention our need to the recovery module here.
  450.  *
  451.  * Results:
  452.  *    None.
  453.  *
  454.  * Side effects:
  455.  *    Marks the handle as needing recovery.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459. ENTRY void
  460. Fsutil_WantRecovery(hdrPtr)
  461.     Fs_HandleHeader *hdrPtr;    /* Handle needing recovery. The handle should
  462.                  * start with a FsRemoteHandle struct. */
  463. {
  464.     register Fsutil_RecoveryInfo *recovPtr = &((Fsrmt_IOHandle *)hdrPtr)->recovery;
  465.     if (!RemoteHandle(hdrPtr)) {
  466.     printf( "Fsutil_WantRecovery: no recovery for %s handles\n",
  467.         Fsutil_FileTypeToString(hdrPtr->fileID.type));
  468.     } else {
  469.     /*
  470.      * The monitor lock is embedded in RemoteIOHandles so we can
  471.      * only lock/unlock with the right kind of handle.
  472.      */
  473.     LOCK_MONITOR;
  474.     fs_Stats.recovery.wants++;
  475.     recovPtr->flags |= RECOVERY_NEEDED;
  476.     UNLOCK_MONITOR;
  477.     }
  478. }
  479.  
  480. /*
  481.  *----------------------------------------------------------------------
  482.  *
  483.  * Fsutil_AttemptRecovery --
  484.  *
  485.  *    Attempt recovery if the server appears up.  This is called
  486.  *    (in the background) by the block cleaner if it gets a stale
  487.  *    handle error on a write-back.
  488.  *
  489.  * Results:
  490.  *    None.
  491.  *
  492.  * Side effects:
  493.  *    Invokes the reopen procedure if the server responds to an RPC.
  494.  *
  495.  *----------------------------------------------------------------------
  496.  */
  497. void
  498. Fsutil_AttemptRecovery(data, callInfoPtr)
  499.     ClientData        data;        /* Ref to Fs_HandleHeader */
  500.     Proc_CallInfo    *callInfoPtr;
  501. {
  502.     register Fs_HandleHeader *hdrPtr =
  503.         (Fs_HandleHeader *)data;
  504.  
  505.     if (!RemoteHandle(hdrPtr)) {
  506.     /*
  507.      * We get called on a local naming request-response stream after the
  508.      * pseudo-filesystem server crashes.  There is no recovery possible
  509.      * so we just return an error and the naming operation fails.
  510.      */
  511.     printf( "Fsutil_AttemptRecovery, no recovery for type: %s\n",
  512.         Fsutil_FileTypeToString(hdrPtr->fileID.type));
  513.     return;
  514.     }
  515.     if (!Recov_IsHostDown(hdrPtr->fileID.serverID)) {
  516.     Fsutil_Reopen(hdrPtr->fileID.serverID, (ClientData)NIL);
  517.     }
  518.     callInfoPtr->interval = 0;    /* no more callbacks, please */
  519.     return;
  520. }
  521.  
  522. /*
  523.  *----------------------------------------------------------------------
  524.  *
  525.  * Fsutil_WaitForRecovery --
  526.  *
  527.  *    Wait until recovery actions have completed for the stream.
  528.  *    This will return failure codes if the recovery aborts.
  529.  *    The wait is interruptable by a signal so the user can abort.
  530.  *
  531.  * Results:
  532.  *    SUCCESS unless there was a recovery error or a signal came in.
  533.  *
  534.  * Side effects:
  535.  *    Block the process.
  536.  *
  537.  *----------------------------------------------------------------------
  538.  */
  539. ReturnStatus
  540. Fsutil_WaitForRecovery(hdrPtr, rpcStatus)
  541.     register Fs_HandleHeader    *hdrPtr;
  542.     ReturnStatus        rpcStatus;    /* Status that caused us to
  543.                          * need recovery. */
  544. {
  545.     ReturnStatus        status = SUCCESS;
  546.  
  547.     if (!RemoteHandle(hdrPtr)) {
  548.     /*
  549.      * We get called on a local naming request-response stream after the
  550.      * pseudo-filesystem server crashes.  There is no recovery possible
  551.      * so we just return an error and the naming operation fails.
  552.      */
  553.     printf( "Fsutil_WaitForRecovery, no recovery for type: %s\n",
  554.         Fsutil_FileTypeToString(hdrPtr->fileID.type));
  555.     return(FAILURE);
  556.     } else if (!Fsutil_HandleValid(hdrPtr)) {
  557.     /*
  558.      * Handle has already failed recovery.
  559.      */
  560.     return(FAILURE);
  561.     }
  562.     /*
  563.      * If our caller got a stale handle then the server is probably up
  564.      * we try to re-establish state with the server now.  Otherwise
  565.      * we depend on a reboot callback to invoke Fsutil_Reopen.
  566.      */
  567.     if (rpcStatus == FS_STALE_HANDLE) {
  568.     Fsutil_FileError(hdrPtr, "", rpcStatus);
  569.     if (!Recov_IsHostDown(hdrPtr->fileID.serverID)) {
  570.         Fsutil_Reopen(hdrPtr->fileID.serverID, (ClientData)NIL);
  571.     }
  572.     }
  573.     status = RecoveryWait(&((Fsrmt_IOHandle *)hdrPtr)->recovery);
  574.     return(status);
  575. }
  576.  
  577. /*
  578.  *----------------------------------------------------------------------
  579.  *
  580.  * RecoveryWait --
  581.  *
  582.  *    Wait until recovery actions have completed for the stream.
  583.  *    This will return failure codes if the recovery aborts.
  584.  *
  585.  * Results:
  586.  *    SUCCESS unless there was a recovery error.
  587.  *
  588.  * Side effects:
  589.  *    Block the process.
  590.  *
  591.  *----------------------------------------------------------------------
  592.  */
  593. ENTRY ReturnStatus
  594. RecoveryWait(recovPtr)
  595.     Fsutil_RecoveryInfo *recovPtr;
  596. {
  597.     register ReturnStatus status = SUCCESS;
  598.     LOCK_MONITOR;
  599.     while (recovPtr->flags & RECOVERY_NEEDED) {
  600.     if (Sync_Wait(&recovPtr->reopenComplete, TRUE)) {
  601.         status = GEN_ABORTED_BY_SIGNAL;
  602.         fs_Stats.recovery.waitAbort++;
  603.         break;
  604.     }
  605.     }
  606.     if (recovPtr->flags & RECOVERY_FAILED) {
  607.     status = recovPtr->status;
  608.     fs_Stats.recovery.waitFailed++;
  609.     } else if (status == SUCCESS) {
  610.     fs_Stats.recovery.waitOK++;
  611.     }
  612.     UNLOCK_MONITOR;
  613.     return(status);
  614. }
  615.  
  616. /*
  617.  *----------------------------------------------------------------------------
  618.  *
  619.  * RecoveryComplete --
  620.  *
  621.  *    Mark a remote handle as having competed recovery actions.  The waiting
  622.  *    process is not woken up yet, however, because it may also depend
  623.  *    on recovery of the shadow streams kept on the server.  FsHandleReopen
  624.  *    will call RecoveryNotify to poke waiters after all handles have been
  625.  *    recovered.  Note that this procedure won't mark the handle as
  626.  *    having completed recovery if the error status indicates a timeout.
  627.  *
  628.  * Results:
  629.  *    None.
  630.  *
  631.  * Side effects:
  632.  *    The handle is marked as having competed recovery if the error
  633.  *    status does not indicate another communcation fail with the server.
  634.  *
  635.  *----------------------------------------------------------------------------
  636.  *
  637.  */
  638. ENTRY static void
  639. RecoveryComplete(recovPtr, status)
  640.     Fsutil_RecoveryInfo *recovPtr;
  641.     ReturnStatus status;
  642. {
  643.     LOCK_MONITOR;
  644.  
  645.     recovPtr->status = status;
  646.     switch(status) {
  647.     case RPC_TIMEOUT:
  648.     case RPC_SERVICE_DISABLED:
  649.         fs_Stats.recovery.timeout++;
  650.         break;
  651.     case FS_FILE_REMOVED:
  652.         recovPtr->flags |= RECOVERY_FAILED|RECOVERY_COMPLETE;
  653.         fs_Stats.recovery.deleted++;
  654.         break;
  655.     default:
  656.         recovPtr->flags |= RECOVERY_FAILED|RECOVERY_COMPLETE;
  657.         fs_Stats.recovery.failed++;
  658.         break;
  659.      case SUCCESS:
  660.         recovPtr->flags |= RECOVERY_COMPLETE;
  661.         fs_Stats.recovery.succeeded++;
  662.         break;
  663.     }
  664.  
  665.     UNLOCK_MONITOR;
  666. }
  667.  
  668. /*
  669.  *----------------------------------------------------------------------------
  670.  *
  671.  * RecoveryNotify --
  672.  *
  673.  *    Wakeup processes waiting on recovery for a handle, if appropriate.
  674.  *    This is called from FsReopenHandle after all handles, both I/O
  675.  *    handles and top-level stream, have been recovered.
  676.  *
  677.  * Results:
  678.  *    None.
  679.  *
  680.  * Side effects:
  681.  *    Processes waiting on the handle are awakened and the RECOVERY_NEEDED
  682.  *    flags is cleared from the recovery flags.
  683.  *
  684.  *----------------------------------------------------------------------------
  685.  *
  686.  */
  687. ENTRY static void
  688. RecoveryNotify(recovPtr)
  689.     register Fsutil_RecoveryInfo *recovPtr;
  690. {
  691.     LOCK_MONITOR;
  692.  
  693.     if (recovPtr->flags & RECOVERY_COMPLETE) {
  694.     recovPtr->flags &= ~(RECOVERY_COMPLETE|RECOVERY_NEEDED);
  695.     Sync_Broadcast(&recovPtr->reopenComplete);
  696.     }
  697.  
  698.     UNLOCK_MONITOR;
  699. }
  700.  
  701. /*
  702.  *----------------------------------------------------------------------
  703.  *
  704.  * Fsutil_RecoveryNeeded --
  705.  *
  706.  *    Returns TRUE if recovery is pending for the handle.  This is
  707.  *    called when scavenging a remote file handle to make sure noone
  708.  *    is waiting for recovery on the handle.
  709.  *
  710.  * Results:
  711.  *    TRUE or FALSE.
  712.  *
  713.  * Side effects:
  714.  *    None.
  715.  *
  716.  *----------------------------------------------------------------------
  717.  */
  718. ENTRY Boolean
  719. Fsutil_RecoveryNeeded(recovPtr)
  720.     Fsutil_RecoveryInfo *recovPtr;
  721. {
  722.     register Boolean recovWanted;
  723.     LOCK_MONITOR;
  724.     recovWanted = (recovPtr->flags & RECOVERY_NEEDED);
  725.     UNLOCK_MONITOR;
  726.     return(recovWanted);
  727. }
  728.  
  729. /*
  730.  *----------------------------------------------------------------------
  731.  *
  732.  * RecoveryFailed --
  733.  *
  734.  *    Returns TRUE if recovery has failed on the handle.  This is
  735.  *    called when recovering streams to see if the I/O handle is ok.
  736.  *
  737.  * Results:
  738.  *    TRUE or FALSE.
  739.  *
  740.  * Side effects:
  741.  *    None.
  742.  *
  743.  *----------------------------------------------------------------------
  744.  */
  745. ENTRY static Boolean
  746. RecoveryFailed(recovPtr)
  747.     Fsutil_RecoveryInfo *recovPtr;
  748. {
  749.     register Boolean recovFailed;
  750.     LOCK_MONITOR;
  751.     recovFailed = (recovPtr->flags & RECOVERY_FAILED);
  752.     UNLOCK_MONITOR;
  753.     return(recovFailed);
  754. }
  755.  
  756. /*
  757.  *----------------------------------------------------------------------------
  758.  *
  759.  * FsRemoteHandleScavange --
  760.  *
  761.  *    Scavenging routine for remote handles, not including remote
  762.  *    file handles. This nukes the handle if there are no uses of
  763.  *    it and it doesn't need recovery.
  764.  *
  765.  * Results:
  766.  *    TRUE if the handle was removed.
  767.  *
  768.  * Side effects:
  769.  *    Either removes or unlocks the handle.
  770.  *
  771.  *----------------------------------------------------------------------------
  772.  *
  773.  */
  774. Boolean
  775. Fsutil_RemoteHandleScavenge(hdrPtr)
  776.     Fs_HandleHeader *hdrPtr;
  777. {
  778.     if (OkToScavenge(&((Fsrmt_IOHandle *)hdrPtr)->recovery)) {
  779.     Fsutil_RecoverySyncLockCleanup(&((Fsrmt_IOHandle *)hdrPtr)->recovery);
  780.     Fsutil_HandleRemove(hdrPtr);
  781.     return(TRUE);
  782.     } else {
  783.     Fsutil_HandleUnlock(hdrPtr);
  784.     return(FALSE);
  785.     }
  786. }
  787.  
  788. /*
  789.  *----------------------------------------------------------------------------
  790.  *
  791.  * OkToScavenge --
  792.  *
  793.  *    Internal routine to check monitored state.  This returns TRUE if
  794.  *    the handle should be scavenged, in which case our caller can
  795.  *    remove the handle, or FALSE, in which our caller should just
  796.  *    unlock it.
  797.  *
  798.  * Results:
  799.  *    None.
  800.  *
  801.  * Side effects:
  802.  *    None.
  803.  *
  804.  *----------------------------------------------------------------------------
  805.  *
  806.  */
  807. static ENTRY Boolean
  808. OkToScavenge(recovPtr)
  809.     register Fsutil_RecoveryInfo *recovPtr;
  810. {
  811.     register Boolean okToScavenge = FALSE;
  812.     LOCK_MONITOR;
  813.     if (recovPtr->use.ref == 0 &&
  814.     (recovPtr->flags & RECOVERY_NEEDED) == 0) {
  815.     okToScavenge = TRUE;
  816.     }
  817.     UNLOCK_MONITOR;
  818.     return(okToScavenge);
  819. }
  820.  
  821. /*
  822.  *----------------------------------------------------------------------
  823.  *
  824.  * Fsutil_ClientCrashed --
  825.  *
  826.  *    Clean up state after a host goes down.  Mainly we want to close
  827.  *    files opened on that client.  We also take care to reset various
  828.  *    watchdogs like the bit that turns off opens until re-opens are done.
  829.  *
  830.  * Results:
  831.  *    None.
  832.  *
  833.  * Side effects:
  834.  *    Cleans up references the client had to files.  Clears the
  835.  *    CLT_RECOV_IN_PROGRESS bit from the client recovery state.
  836.  *
  837.  *----------------------------------------------------------------------
  838.  */
  839. /*ARGSUSED*/
  840. void
  841. Fsutil_ClientCrashed(spriteID, clientData)
  842.     int spriteID;        /* Client that crashed */
  843.     ClientData clientData;    /* IGNORED */
  844. {
  845.     fs_Stats.recovery.clientCrashed++;
  846.     /*
  847.      * Reset the 'recovery in progress' bit (it would be set if the
  848.      * client crashed during recovery) so the client can open files
  849.      * the next time it boots.
  850.      */
  851.     Recov_ClearClientState(spriteID, CLT_RECOV_IN_PROGRESS);
  852.     /*
  853.      * Clean up references to our files.
  854.      */
  855.     Fsutil_RemoveClient(spriteID);
  856. }
  857.  
  858. /*
  859.  *----------------------------------------------------------------------------
  860.  *
  861.  * Fsutil_RemoveClient --
  862.  *
  863.  *    Go through all of the handles and delete all references to the
  864.  *    handle for the client.  This is to be called when a client reboots.
  865.  *    The clientKill procedure for each I/O handle type must either
  866.  *    unlock the handle or remove it after cleaning up.
  867.  *
  868.  * Results:
  869.  *    None.
  870.  *
  871.  * Side effects:
  872.  *    Calls the stream-type-specific clientKill procedures.
  873.  *
  874.  *----------------------------------------------------------------------------
  875.  *
  876.  */
  877.  
  878. void
  879. Fsutil_RemoveClient(clientID)
  880.     int        clientID;    /* The client to remove the files for. */
  881. {
  882.     Hash_Search            hashSearch;
  883.     register    Fs_HandleHeader    *hdrPtr;
  884.  
  885.     Hash_StartSearch(&hashSearch);
  886.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  887.      hdrPtr != (Fs_HandleHeader *) NIL;
  888.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  889.     (*fsio_StreamOpTable[hdrPtr->fileID.type].clientKill)(hdrPtr, clientID);
  890.     }
  891. }
  892.  
  893.  
  894. #ifdef not_used
  895.  
  896. /*
  897.  *----------------------------------------------------------------------
  898.  *
  899.  * FsRecoveryStarting --
  900.  *
  901.  *    This tells the server that we are starting recovery so that it
  902.  *    can prevent open requests by us.
  903.  *
  904.  * Results:
  905.  *    None.
  906.  *
  907.  * Side effects:
  908.  *    An RPC to the server.
  909.  *
  910.  *----------------------------------------------------------------------
  911.  */
  912. ENTRY void
  913. FsRecoveryStarting(serverID)
  914.     int serverID;        /* Server we are recovering with */
  915. {
  916.     Rpc_Storage storage;
  917.     int flags = CLT_RECOV_IN_PROGRESS;
  918.  
  919.     storage.requestParamPtr = (Address)&flags;
  920.     storage.requestParamSize = sizeof(int);
  921.     storage.requestDataPtr = (Address)NIL;
  922.     storage.requestDataSize = 0;
  923.     storage.replyParamPtr = (Address)NIL;
  924.     storage.replyParamSize = 0;
  925.     storage.replyDataPtr = (Address)NIL;
  926.     storage.replyDataSize = 0;
  927.  
  928.     status = Rpc_Call(serverID, RPC_FS_RECOVERY, &storage);
  929.     if (status != SUCCESS) {
  930.     printf( "FsRecoveryDone: got status %x\n", status);
  931.     }
  932. }
  933. #endif not_used
  934.  
  935. /*
  936.  *----------------------------------------------------------------------
  937.  *
  938.  * RecoveryDone --
  939.  *
  940.  *    This tells the server that we are done with recovery so that it
  941.  *    will start handling open requests from us.
  942.  *
  943.  * Results:
  944.  *    None.
  945.  *
  946.  * Side effects:
  947.  *    An RPC to the server.
  948.  *
  949.  *----------------------------------------------------------------------
  950.  */
  951. ENTRY static void
  952. RecoveryDone(serverID)
  953.     int serverID;        /* Server we are recovering with */
  954. {
  955.     Rpc_Storage storage;
  956.     ReturnStatus status;
  957.     int flags = 0;
  958.  
  959.     storage.requestParamPtr = (Address)&flags;
  960.     storage.requestParamSize = sizeof(int);
  961.     storage.requestDataPtr = (Address)NIL;
  962.     storage.requestDataSize = 0;
  963.     storage.replyParamPtr = (Address)NIL;
  964.     storage.replyParamSize = 0;
  965.     storage.replyDataPtr = (Address)NIL;
  966.     storage.replyDataSize = 0;
  967.  
  968.     status = Rpc_Call(serverID, RPC_FS_RECOVERY, &storage);
  969.     if (status != SUCCESS) {
  970.     printf( "RecoveryDone: got status %x\n", status);
  971.     } else {
  972.     fs_Stats.recovery.number++;
  973.     }
  974. }
  975.  
  976. /*
  977.  *----------------------------------------------------------------------
  978.  *
  979.  * Fsutil_RpcRecovery --
  980.  *
  981.  *    Rpc server stub for RPC_FS_RECOVERY RPC.  The client us
  982.  *    before and after it is re-opening its files.  This lets us
  983.  *    block out regular open requests until the re-opening is done.
  984.  *
  985.  * Results:
  986.  *    None.
  987.  *
  988.  * Side effects:
  989.  *    Maintains the "client is recovering" state bit.
  990.  *
  991.  *----------------------------------------------------------------------
  992.  */
  993. /*ARGSUSED*/
  994. ReturnStatus
  995. Fsutil_RpcRecovery(srvToken, clientID, command, storagePtr)
  996.     ClientData srvToken;    /* Handle on server process passed to
  997.                  * Rpc_Reply */
  998.     int clientID;        /* Sprite ID of client host */
  999.     int command;        /* Command identifier */
  1000.     Rpc_Storage *storagePtr;    /* The request fields refer to the request
  1001.                  * buffers and also indicate the exact amount
  1002.                  * of data in the request buffers.  The reply
  1003.                  * fields are initialized to NIL for the
  1004.                  * pointers and 0 for the lengths.  This can
  1005.                  * be passed to Rpc_Reply */
  1006. {
  1007.     int *flagsPtr = (int *)storagePtr->requestParamPtr;
  1008.     if (*flagsPtr & CLT_RECOV_IN_PROGRESS) {
  1009.     if ((Recov_GetClientState(clientID) & CLT_RECOV_IN_PROGRESS) == 0) {
  1010.         fsutil_NumRecovering++;
  1011.         if (fsutil_NumRecovering == 1) {
  1012.         Net_HostPrint(clientID, "initiated client recovery\n");
  1013.         }
  1014.         Recov_SetClientState(clientID, CLT_RECOV_IN_PROGRESS);
  1015.     }
  1016.     fs_Stats.recovery.clientRecovered++;
  1017.     } else {
  1018.     Recov_ClearClientState(clientID, CLT_RECOV_IN_PROGRESS);
  1019.     fsutil_NumRecovering--;
  1020.     if (fsutil_NumRecovering == 0) {
  1021.         Net_HostPrint(clientID, "completed client recovery\n");
  1022.     }
  1023.     }
  1024.     Rpc_Reply(srvToken, SUCCESS, storagePtr, (int(*)())NIL, (ClientData)NIL);
  1025.     return(SUCCESS);
  1026. }
  1027.  
  1028.  
  1029. /*
  1030.  *----------------------------------------------------------------------
  1031.  *
  1032.  * Fsutil_FsRecovInfo --
  1033.  *
  1034.  *    Info, including file names, about recovery and file status for testing.
  1035.  *
  1036.  * Results:
  1037.  *    SUCCESS or not.
  1038.  *
  1039.  * Side effects:
  1040.  *    None.
  1041.  *
  1042.  *----------------------------------------------------------------------
  1043.  */
  1044. ReturnStatus
  1045. Fsutil_FsRecovInfo(length, resultPtr, lengthNeededPtr)
  1046.     int                length;        /* size of data buffer */
  1047.     Fsutil_FsRecovNamedStats    *resultPtr;    /* data buffer */
  1048.     int                *lengthNeededPtr;
  1049. {
  1050.     Hash_Search            hashSearch;
  1051.     Fs_HandleHeader        *hdrPtr;
  1052.     Fsutil_FsRecovNamedStats    *infoPtr;
  1053.     int                numNeeded;
  1054.     int                numAvail;
  1055.     Fs_HandleHeader        *testHandlePtr;
  1056.  
  1057.     if (resultPtr != (Fsutil_FsRecovNamedStats *) NIL) {
  1058.     bzero((char *) resultPtr, length);
  1059.     }
  1060.     numNeeded = 0;
  1061.     numAvail = length / sizeof (Fsutil_FsRecovNamedStats);
  1062.  
  1063.     infoPtr = (Fsutil_FsRecovNamedStats *) resultPtr;
  1064.  
  1065.     Hash_StartSearch(&hashSearch);
  1066.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  1067.      hdrPtr != (Fs_HandleHeader *) NIL;
  1068.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1069.  
  1070.     numNeeded++;
  1071.     if (numNeeded > numAvail) {
  1072.         Fsutil_HandleUnlock(hdrPtr);
  1073.         continue;
  1074.     }
  1075.     if (hdrPtr->fileID.type == FSIO_STREAM) {
  1076.         Fs_Stream    *streamPtr;
  1077.  
  1078.         streamPtr = (Fs_Stream *) hdrPtr;
  1079.  
  1080.         infoPtr->streamRefCount = hdrPtr->refCount;
  1081.         infoPtr->mode = streamPtr->flags;
  1082.         infoPtr->streamHandle = TRUE;
  1083.  
  1084.         testHandlePtr = streamPtr->ioHandlePtr;
  1085.     } else {
  1086.         infoPtr->streamHandle = FALSE;
  1087.         testHandlePtr = hdrPtr;
  1088.     }
  1089.  
  1090.     if (testHandlePtr != (Fs_HandleHeader *) NIL) {
  1091.         infoPtr->fileID = testHandlePtr->fileID;
  1092.  
  1093.         if (fsio_StreamRecovTestFuncs[testHandlePtr->fileID.type].refFunc
  1094.             != (int ((*)())) NIL) {
  1095.         infoPtr->refCount =
  1096.             (*(fsio_StreamRecovTestFuncs[
  1097.             testHandlePtr->fileID.type]).refFunc) (testHandlePtr);
  1098.         }
  1099.         if (fsio_StreamRecovTestFuncs[
  1100.             testHandlePtr->fileID.type].numBlocksFunc !=
  1101.             (int ((*)())) NIL) {
  1102.         infoPtr->numBlocks =
  1103.             (*(fsio_StreamRecovTestFuncs[
  1104.             testHandlePtr->fileID.type]).numBlocksFunc)
  1105.             (testHandlePtr);
  1106.         }
  1107.         if (fsio_StreamRecovTestFuncs[
  1108.             testHandlePtr->fileID.type].numDirtyBlocksFunc
  1109.             != (int ((*)())) NIL) {
  1110.         infoPtr->numDirtyBlocks =
  1111.             (*(fsio_StreamRecovTestFuncs[
  1112.             testHandlePtr->fileID.type]).numDirtyBlocksFunc)
  1113.             (testHandlePtr);
  1114.         }
  1115.         (void)strncpy(infoPtr->name, Fsutil_HandleName(testHandlePtr), 49);
  1116.         infoPtr->name[50] = '\0';
  1117.     }
  1118.     infoPtr++;
  1119.     Fsutil_HandleUnlock(hdrPtr);
  1120.     }
  1121.     *lengthNeededPtr = numNeeded * sizeof (Fsutil_FsRecovNamedStats);
  1122.  
  1123.     return SUCCESS;
  1124. }
  1125.  
  1126. /*
  1127.  *----------------------------------------------------------------------------
  1128.  *
  1129.  * Fsutil_TestForHandles --
  1130.  *
  1131.  *    Called to see if we still have handles for the given serverID.
  1132.  *
  1133.  * Results:
  1134.  *    Number of file and device handles for server in question.
  1135.  *
  1136.  * Side effects:
  1137.  *    None.
  1138.  *
  1139.  *----------------------------------------------------------------------------
  1140.  */
  1141. int
  1142. Fsutil_TestForHandles(serverID)
  1143.     int        serverID;    /* Server we're interested in. */
  1144. {
  1145.     Hash_Search            hashSearch;
  1146.     register    Fs_HandleHeader    *hdrPtr;
  1147.     int                count = 0;
  1148.  
  1149.     Hash_StartSearch(&hashSearch);
  1150.     for (hdrPtr = Fsutil_GetNextHandle(&hashSearch);
  1151.      hdrPtr != (Fs_HandleHeader *) NIL;
  1152.          hdrPtr = Fsutil_GetNextHandle(&hashSearch)) {
  1153.      if (hdrPtr->fileID.serverID == serverID) {
  1154.         switch(hdrPtr->fileID.type) {
  1155. /*
  1156.         case FSIO_RMT_PSEUDO_STREAM:
  1157.         case FSIO_STREAM:
  1158. */
  1159.         case FSIO_RMT_FILE_STREAM:
  1160.         case FSIO_RMT_DEVICE_STREAM:
  1161.         count++;
  1162.         break;
  1163.         default:
  1164.         break;
  1165.         }
  1166.     }
  1167.     Fsutil_HandleUnlock(hdrPtr);
  1168.     }
  1169.     return count;
  1170. }
  1171.  
  1172.